home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 23 / Amiga Format AFCD23 (Feb 1998, Issue 107).iso / -in_the_mag- / emulation / consoles / vision-8 / sources / msdos.c < prev    next >
C/C++ Source or Header  |  1997-12-12  |  10KB  |  282 lines

  1. /** Vision8: CHIP8 emulator *************************************************/
  2. /**                                                                        **/
  3. /**                                MSDOS.c                                 **/
  4. /**                                                                        **/
  5. /** This file contains the MS-DOS implementation                           **/
  6. /**                                                                        **/
  7. /** Copyright (C) Marcel de Kogel 1997                                     **/
  8. /**     You are not allowed to distribute this software commercially       **/
  9. /**     Please, notify me, if you make any changes to this file            **/
  10. /****************************************************************************/
  11.  
  12. #include "CHIP8.h"
  13.  
  14. #include <conio.h>
  15. #include <dos.h>
  16. #include <stdio.h>
  17. #include <time.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20.  
  21. static volatile byte timer_count;               /* 55Hz counter             */
  22. static volatile byte keyb_status[256];          /* If 1, key is pressed     */
  23. static void interrupt (*old_int8) (void);       /* Old timer interrupt      */
  24. static void interrupt (*old_int9) (void);       /* Old keyboard interrupt   */
  25. static int  sync=1;                             /* If 0, do not sync        */
  26.                                                 /* emulation                */
  27. static byte uperiod=1;                          /* number of interrupts per */
  28.                                                 /* screen update            */
  29.  
  30. /****************************************************************************/
  31. /* Turn sound on                                                            */
  32. /****************************************************************************/
  33. void chip8_sound_on (void)
  34. {
  35.  sound (500);
  36. }
  37.  
  38. /****************************************************************************/
  39. /* Turn sound off                                                           */
  40. /****************************************************************************/
  41. void chip8_sound_off (void)
  42. {
  43.  nosound ();
  44. }
  45.  
  46. /****************************************************************************/
  47. /* Update the display                                                       */
  48. /****************************************************************************/
  49. static void update_display (void)
  50. {
  51.  int i,j;
  52.  byte far *p=MK_FP(0xb800,1448);                /* Get a pointer to VRAM    */
  53.  byte *q=chip8_display;
  54.  byte c;
  55.  for (i=0;i<32;++i)                             /* 32 rows                  */
  56.  {
  57.   for (j=0;j<64;++j)                            /* 64 columns               */
  58.   {
  59.    c=*q^0x55;                                   /* background=cyan,         */
  60.                                                 /* foreground=magenta       */
  61.    p[0]=p[0x2000]=p[80]=p[0x2000+80]=c;         /* draw a 4x4 box           */
  62.    p++;                                         /* update pointers          */
  63.    q++;
  64.   }
  65.   p+=16+80;
  66.  }
  67. }
  68.  
  69. /****************************************************************************/
  70. /* Update CHIP8 keyboard status                                             */
  71. /****************************************************************************/
  72. static void check_keys (void)
  73. {
  74.  struct keyinfo_struct
  75.  {
  76.   byte code,key;
  77.  };
  78.  static struct keyinfo_struct keyinfo[]=
  79.  {
  80.   { 0x02,0x01 }, { 0x03,0x02 }, { 0x04,0x03 }, { 0x05,0x0c },
  81.   { 0x10,0x04 }, { 0x11,0x05 }, { 0x12,0x06 }, { 0x13,0x0d },
  82.   { 0x1e,0x07 }, { 0x1f,0x08 }, { 0x20,0x09 }, { 0x21,0x0e },
  83.   { 0x2c,0x0a }, { 0x2d,0x00 }, { 0x2e,0x0b }, { 0x2f,0x0f },
  84.                             
  85.   { 0x47,0x01 }, { 0x48,0x02 }, { 0x49,0x03 }, { 0xb5,0x0c },
  86.   { 0x4b,0x04 }, { 0x4c,0x05 }, { 0x4d,0x06 }, { 0x37,0x0d },
  87.   { 0x4f,0x07 }, { 0x50,0x08 }, { 0x51,0x09 }, { 0x4a,0x0e },
  88.   { 0x52,0x0a }, { 0x53,0x00 }, { 0x9c,0x0b }, { 0x4e,0x0f },
  89.  
  90.   { 0x00,0x00 }
  91.  };
  92.  byte i;
  93.  /* start with all keys up */
  94.  memset (chip8_keys,0,sizeof(chip8_keys));
  95.  /* now check which are pressed */
  96.  for (i=0;keyinfo[i].code;++i)
  97.   if (keyb_status[keyinfo[i].code])
  98.    chip8_keys[keyinfo[i].key]=1;
  99.  /* check if ESC or F10 is being held down */
  100.  if (keyb_status[0x01] || keyb_status[0x44]) chip8_running=0;
  101.  /* what about F1 ? */
  102.  if (keyb_status[0x3b]) chip8_reset();
  103. }
  104.  
  105. /****************************************************************************/
  106. /* Return time passed in 55th seconds                                       */
  107. /****************************************************************************/
  108. static byte get_timer_count (void)
  109. {
  110.  return timer_count;
  111. }
  112.  
  113. /****************************************************************************/
  114. /* Update keyboard and display, sync emulation with hardware timer          */
  115. /****************************************************************************/
  116. void chip8_interrupt (void)
  117. {
  118.  static int ucount=1;
  119.  if (!--ucount)
  120.  {
  121.   ucount=uperiod;
  122.   update_display ();
  123.  }
  124.  check_keys ();
  125.  if (sync)
  126.  {
  127.   while (get_timer_count()==0);
  128.   timer_count=0;
  129.  }
  130. }
  131.  
  132. /****************************************************************************/
  133. /* New timer interrupt routine                                              */
  134. /****************************************************************************/
  135. static void interrupt new_int8 (void)
  136. {
  137.  static int icount=3;
  138.  ++timer_count;                                 /* increment counter        */
  139.  if (!--icount)                                 /* call old routine 18,2    */
  140.  { icount=3; (*old_int8)(); }                   /* times per second         */
  141.  else
  142.  { outportb (0x20,0x20); }                      /* acknowledge interrupt    */
  143. }
  144.  
  145. /****************************************************************************/
  146. /* New keyboard interrupt routine                                           */
  147. /****************************************************************************/
  148. static void interrupt new_int9 (void)
  149. {
  150.  unsigned code;
  151.  static int extkey;
  152.  code=inportb (0x60);                           /* get scancode             */
  153.  if (code<0xE0)                                 /* ignore codes >0xE0       */
  154.  {
  155.   keyb_status[(code&0x7f)+extkey]=((code&0x80)==0);
  156.   extkey=0;
  157.  }
  158.  else if (code==0xE0) extkey=128;
  159.  code=inportb (0x61);                           /* acknowledge interrupt    */
  160.  outportb (0x61,code | 0x80);
  161.  outportb (0x61,code);
  162.  outportb (0x20,0x20);
  163. }
  164.  
  165. /****************************************************************************/
  166. /* Parse command line options and start emulation                           */
  167. /****************************************************************************/
  168. int main (int argc,char *argv[])
  169. {
  170.  FILE *f;
  171.  union REGS r;
  172.  byte old_video_mode;
  173.  int i,j,k,misparm;
  174.  char *options[] = { "h","up","ip","s",NULL };
  175.  char *program=NULL;
  176.  chip8_iperiod=15;
  177.  printf ("Vision-8: Portable CHIP8 emulator\n"
  178.          "Copyright (C) 1997  Marcel de Kogel\n");
  179.  for (i=1,k=0;i<argc;++i)
  180.  {
  181.   misparm=0;
  182.   if (*argv[i]!='-')
  183.    switch (k++)
  184.    {
  185.     case 0:  program=argv[i];
  186.              break;
  187.     default: printf("Excessive filename '%s'\n",argv[i]);
  188.              return 1;
  189.    }
  190.   else
  191.   {    
  192.    for (j=0;options[j];j++)
  193.     if (!strcmp(argv[i]+1,options[j])) break;
  194.    switch (j)
  195.    {
  196.     case 0:
  197.      printf ("Usage: v8 [options] <filename>\n"
  198.              "Available options are:\n"
  199.              " -h          - Print this help page\n"
  200.              " -up <value> - Select number of interrupts per screen update [1]\n"
  201.              " -ip <value> - Select number of opcodes per interrupt [15]\n"
  202.              " -s <value>  - Select synchronisation mode [1]\n"
  203.              "               0 - Do not sync emulation\n"
  204.              "               1 - Sync emulation to 55Hz clock\n");
  205.              return 0;
  206.     case 1:  i++;
  207.              if (i<argc) uperiod=atoi(argv[i]);
  208.              else misparm=1;
  209.              break;
  210.     case 2:  i++;
  211.              if (i<argc) chip8_iperiod=atoi(argv[i]);
  212.              else misparm=1;
  213.              break;
  214.     case 3:  i++;
  215.              if (i<argc) sync=atoi(argv[i]);
  216.              else misparm=1;
  217.              break;
  218.     default: printf ("Wrong option '%s'\n",argv[i]);
  219.              return 1;
  220.    }
  221.    if (misparm)
  222.    {
  223.     printf("%s: Missing parameter\n",argv[i-1]);
  224.     return 1;
  225.    }
  226.   }
  227.  }
  228.  if (!program)
  229.  {
  230.   puts ("No program name given\n");
  231.   return 1;
  232.  }
  233.  printf ("Opening CHIP8 program %s... ",program);
  234.  f=fopen (program,"rb");
  235.  if (!f)
  236.  {
  237.   puts ("FAILED");
  238.   return 1;
  239.  }
  240.  printf ("OK\n Reading... ");
  241.  i=fread (chip8_mem+0x200,1,4096-0x200,f);
  242.  fclose (f);
  243.  if (i==0)
  244.  {
  245.   puts ("File is empty");
  246.   return 1;
  247.  }
  248.  printf ("%d bytes loaded\n",i);
  249.  printf ("Press any key to start emulation...");
  250.  getch ();
  251.  memset (&r,0,sizeof(r));                       /* get current video mode   */
  252.  r.h.ah=0x0f;
  253.  int86 (0x10,&r,&r);
  254.  old_video_mode=r.h.al;
  255.  memset (&r,0,sizeof(r));                       /* set 320x200x4 (CGA) mode */
  256.  r.x.ax=0x04;
  257.  int86 (0x10,&r,&r);
  258.  old_int8=getvect (8);                          /* get interrupt vectors    */
  259.  old_int9=getvect (9);
  260.  setvect (8,new_int8);                          /* and set our own          */
  261.  setvect (9,new_int9);
  262.  disable ();                                    /* set timer frequency to   */
  263.  outportb (0x43,0x36);                          /* 55Hz                     */
  264.  outportb (0x40,0x55);
  265.  outportb (0x40,0x55);
  266.  enable ();
  267.  chip8 ();                                      /* start emulation          */
  268.  setvect (8,old_int8);                          /* restore interrupt        */
  269.  setvect (9,old_int9);                          /* vectors                  */
  270.  memset (&r,0,sizeof(r));
  271.  r.x.ax=old_video_mode;                         /* restore original video   */
  272.  int86 (0x10,&r,&r);                            /* mode                     */
  273.  nosound ();                                    /* turn sound off           */
  274.  disable ();                                    /* restore timer frequency  */
  275.  outportb (0x43,0x36);
  276.  outportb (0x40,0);
  277.  outportb (0x40,0);
  278.  enable ();
  279.  return 0;                                      /* all done                 */
  280. }
  281.  
  282.